unit GLGUIEventManager;

interface

uses
  SysUtils,
  GLSGenerics,
  GLGUITokens,
  GLGUIMouseControl,
  GLGUIEvent;

type
  TGLGUIEventClassesList = GList<TGLGUIEventClass>;

  TGLGUIEventManager = class
  private
    FClasses: TGLGUIEventClassesList;
    FEvents: TGLGUIEventsList;
    FFocusedObject: TObject;
    FHighLitedObject: TObject;
    procedure AddClass(AEventClass: TGLGUIEventClass);
    function GetEvent(AIndex: Integer): TGLGUIEvent;
    function GetEventsCount: Integer;
    function GetFocusedObject: TObject;
    procedure SetFocusedObject(AObject: TObject);
    function GetHighLitedObject: TObject;
    procedure SetHighLitedObject(AObject: TObject);
  public
    constructor Create();
    function FindClass(AEventType: TGLGUIEventType): TGLGUIEventClass;
    function GetOrCreateEvent(AEventType: TGLGUIEventType): TGLGUIEvent;
    Function FindEvent(AEventType: TGLGUIEventType): TGLGUIEvent;
    function EventExist(AEventType: TGLGUIEventType): Boolean;
    destructor Destroy; override;
    property Events[AIndex: Integer]: TGLGUIEvent read GetEvent;
    property EventsCount: Integer read GetEventsCount;
    property FocusedObject: TObject read GetFocusedObject
      write SetFocusedObject;
    property HighLitedObject: TObject read GetHighLitedObject
      write SetHighLitedObject;
  end;

function GUIEventManager: TGLGUIEventManager;

procedure RegisterEvent(AEvent: TGLGUIEventClass);
procedure RegisterEvents(AEvents: Array of TGLGUIEventClass);

implementation

uses
  GLGUIBase, GLGUIState;

type
  TGLGUIBaseAccessProvider = class(TGLGUIObject);

{$IFDEF GLS_REGIONES}{$REGION 'Singleton'}{$ENDIF}

var
  vEventManager: TGLGUIEventManager;

function GUIEventManager: TGLGUIEventManager;
begin
  if vEventManager = nil then
    vEventManager := TGLGUIEventManager.Create;
  Result := vEventManager;
end;

{$IFDEF GLS_REGIONES}{$ENDREGION}{$ENDIF}

procedure RegisterEvent(AEvent: TGLGUIEventClass);
begin
  GUIEventManager.AddClass(AEvent);
  GUIEventManager.GetOrCreateEvent(AEvent.ClassName);
end;

procedure RegisterEvents(AEvents: Array of TGLGUIEventClass);
var
  i: Integer;
begin
  for i := 0 to length(AEvents) - 1 do
    RegisterEvent(AEvents[i]);
end;

constructor TGLGUIEventManager.Create();
begin
  FClasses := TGLGUIEventClassesList.Create;
  FEvents := TGLGUIEventsList.Create;
end;

procedure TGLGUIEventManager.AddClass(AEventClass: TGLGUIEventClass);
begin
  FClasses.Add(AEventClass);
end;

function TGLGUIEventManager.FindClass(AEventType: TGLGUIEventType)
  : TGLGUIEventClass;
var
  i: Integer;
begin
  Result := nil;
  for i := 0 to FClasses.Count - 1 do
  begin
    if FClasses.Items[i].ClassName = AEventType then
    begin
      Result := FClasses.Items[i];
      Exit;
    end;
  end;
end;

function TGLGUIEventManager.GetOrCreateEvent(AEventType: TGLGUIEventType)
  : TGLGUIEvent;
var
  vEvent: TGLGUIEvent;
  vClass: TGLGUIEventClass;
begin
  vEvent := FindEvent(AEventType);
  if vEvent = nil then
  begin
    vClass := FindClass(AEventType);
    if vClass <> nil then
      vEvent := TGLGUIEventClass(vClass).Create()
    else
      vEvent := TGLGUIEvent.Create();

    vEvent.EventType := AEventType;
    vEvent.EventPhase := epWorking;
    FEvents.Add(vEvent);
    Result := vEvent;
  end
  else
    Result := vEvent;
end;

function TGLGUIEventManager.FindEvent(AEventType: TGLGUIEventType): TGLGUIEvent;
var
  i: Integer;
  vEvent: TGLGUIEvent;
begin
  Result := nil;
  for i := 0 to FEvents.Count - 1 do
  begin
    vEvent := FEvents.Items[i];
    if vEvent.EventType = AEventType then
    begin
      Result := vEvent;
      Exit;
    end;
  end;
end;

function TGLGUIEventManager.EventExist(AEventType: TGLGUIEventType): Boolean;
begin
  Result := False;
  if Assigned(FindEvent(AEventType)) then
    Result := True;
end;

function TGLGUIEventManager.GetEvent(AIndex: Integer): TGLGUIEvent;
begin
  Result := FEvents.Items[AIndex];
end;

function TGLGUIEventManager.GetEventsCount: Integer;
begin
  Result := FEvents.Count;
end;

function TGLGUIEventManager.GetFocusedObject: TObject;
begin
  Result := FFocusedObject;
end;

procedure TGLGUIEventManager.SetFocusedObject(AObject: TObject);
begin
  if Assigned(FFocusedObject) then
  begin
    TGLGUIObject(FFocusedObject).DispatchFocusUnSet();
  end;
  FFocusedObject := AObject;
end;

function TGLGUIEventManager.GetHighLitedObject: TObject;
begin
  Result := FHighLitedObject;
end;

procedure TGLGUIEventManager.SetHighLitedObject(AObject: TObject);
var
  vObject: TGLGUIObject;
begin
  if AObject <> FHighLitedObject then
  begin
    vObject := TGLGUIObject(FHighLitedObject);
    FHighLitedObject := AObject;
    if Assigned(FHighLitedObject) then
      TGLGUIObject(FHighLitedObject).DispatchHoverSet()
    else
      GLGUICursor.Image := GLGUICursor.DefaultImage;
    if Assigned(vObject) then
    begin
      MouseLeaveEvent.Prepare;
      TGLGUIObject(vObject).DispatchMouseLeaveEvent();
    end;
  end;
end;

destructor TGLGUIEventManager.Destroy;
var
  i: Integer;
begin
  for i := 0 to FEvents.Count - 1 do
    FEvents.Items[i].Free;
  FEvents.Free;
  FClasses.Free;
  inherited;
end;

initialization

finalization

FreeAndNil(vEventManager);

end.
